use crate::commands::jdocker::Jdocker;
use nix::libc::pid_t;
use std::fs;
use std::fs::{exists, File, OpenOptions};
use std::io::Write;
use std::path::Path;
use std::process::Command;

///创建目录(幂等)
pub fn create_dir(path: String) {
    let dir_path = Path::new(&path);
    match exists(dir_path).expect("failed to check dir path") {
        true => match dir_path.is_dir() {
            true => {
                return;
            }
            false => {
                fs::create_dir(path).expect("failed to create directory");
                return;
            }
        },
        false => {
            fs::create_dir(path).expect("failed to create directory");
        }
    };
}
///创建文件(幂等)
pub fn create_file(path: String) {
    let file_path = Path::new(&path);
    match exists(file_path).expect("failed to check file path") {
        true => match file_path.is_file() {
            true => {
                return;
            }
            false => {
                File::create(file_path).expect("failed to create file");
                return;
            }
        },
        false => {
            File::create(file_path).expect("failed to create file");
        }
    }
}
///把容器名和启动容器的1号进程的pid存入'数据库'
pub fn record_pid_and_container_name(pid: pid_t, container_name: String) {
    let jdocker = Jdocker::new();
    let db_dir_path = jdocker.get_db_dir();
    let container_db_file_path = join_dir(db_dir_path, container_name);
    let mut container_db_file = OpenOptions::new()
        .write(true)
        .truncate(true)
        .create(true)
        .open(container_db_file_path)
        .expect("failed to open file");
    container_db_file
        .write_all(pid.to_string().as_bytes())
        .expect("failed to write to file");
}
pub fn log_info(log: String) {
    println!("[info] {}", log);
}
pub fn log_error(log: String) {
    eprintln!("[error] {}", log)
}

///根据镜像名和容器名创建overlayfs所需的目录
pub fn container_fs_dir(image: String, container_name: String) {
    let jdocker_container_dirs = container_fs_dir_get(image, container_name);
    create_dir(jdocker_container_dirs.container_dir.clone());
    create_dir(jdocker_container_dirs.worker_dir.clone());
    create_dir(jdocker_container_dirs.merge_dir.clone());
}
///根据镜像名和容器名生成此次创建容器所需的所有目录(幂等)
pub fn container_fs_dir_get(image_name: String, container_name: String) -> JdockerContainerDirs {
    let jdocker = Jdocker::new();
    //lower目录
    let image_dir = jdocker.get_image_dir();
    let image_dir = join_dir(image_dir, image_name.clone());
    //upper目录
    let container_dir = jdocker.get_container_dir();
    let container_dir = join_dir(container_dir, container_name.clone());
    //worker目录
    let worker_dir = jdocker.get_tmp_dir();
    let worker_dir = join_dir(worker_dir, container_name.clone());
    //merge目录
    let runtime_dir = jdocker.get_runtime_dir();
    let runtime_dir = join_dir(runtime_dir, container_name.clone());
    JdockerContainerDirs {
        image_dir,
        container_dir,
        worker_dir,
        merge_dir: runtime_dir,
    }
}
///根据镜像名和容器名给出数据库文件(幂等)
pub fn container_db( container_name: String) -> String {
    let db_dir = Jdocker::new().get_db_dir();
    join_dir(db_dir, container_name)
}
///一个镜像所生成的一个容器所需的所有目录
#[derive(Debug)]
pub struct JdockerContainerDirs {
    pub image_dir: String,
    pub container_dir: String,
    pub worker_dir: String,
    pub merge_dir: String,
}
///拼接两个路劲和文件
pub fn join_dir(dir1: String, file: String) -> String {
    let path_buf = Path::new(&dir1);
    let path_buf = path_buf.join(&file);
    path_buf.display().to_string()
}

pub fn get_image_name_and_container_name_from_file_name(file_name: String) -> (String, String) {
    let vec = file_name
        .split_once("_")
        .expect("file_name is not format correctly");
    (vec.0.to_string(), vec.1.to_string())
}
pub fn pid_is_alive(pid: String) -> bool {
    let proc_dir = Path::new("/proc");
    let pid_dir = proc_dir.join(pid);
    exists(pid_dir).expect("failed to check process pid")
}
///rm -r -d <string>
pub fn rm_dir_all(path: String) {
    let mut child = Command::new("rm").arg("-r").arg("-d").arg("-f").arg(path).spawn().expect("failed to rm dir");
    child.wait().expect("failed to wait on child");
}
pub fn rm_file(path: String) {
    let mut child = Command::new("rm").arg("-f").arg(path).spawn().expect("failed to file");
    child.wait().expect("failed to wait on child");
}